const {app, BrowserWindow, Tray, Menu, ipcMain, globalShortcut} = require('electron');
const path = require('path');
const {spawn} = require('child_process');
const fs = require('fs');
const http = require('http');
const os = require('os');
const {mkdirSync} = require('fs');
const {appendFile} = require('fs').promises;
const https = require('https');
const querystring = require('querystring');
const mysql = require('mysql2/promise');

// 读取配置文件 - 支持外置配置
function getConfigPath(filename) {
    // 尝试多个可能的配置文件位置，优先级从高到低
    const possiblePaths = [
        // 1. 应用安装根目录（最高优先级，便于用户修改）
        path.join(path.dirname(process.execPath), filename),
        // 2. 应用安装目录下的 config 文件夹
        path.join(path.dirname(process.execPath), 'config', filename),
        // 3. extraResources 目录（electron-builder 的 extraResources 配置）
        path.join(process.resourcesPath || '', filename),
        // 4. app.asar.unpacked 目录
        path.join(__dirname, '..', 'app.asar.unpacked', filename),
        // 5. 相对路径（开发环境）
        path.join(__dirname, filename),
        // 6. 执行目录下的 resources
        path.join(path.dirname(process.execPath), 'resources', filename),
        // 7. resources 子目录
        path.join(__dirname, '..', 'resources', filename)
    ];

    // 找到第一个存在的配置文件
    for (const testPath of possiblePaths) {
        if (fs.existsSync(testPath)) {
            console.log(`使用配置文件: ${testPath}`);
            return testPath;
        }
    }

    // 如果都没找到，返回应用安装根目录路径（用于创建默认配置）
    const defaultPath = path.join(path.dirname(process.execPath), filename);
    console.log(`配置文件未找到，将使用默认路径: ${defaultPath}`);
    return defaultPath;
}

const configPath = getConfigPath('config.json');
let config = {
    autoStart: true,
    minimizeToTray: true,
    port: 5173
};

if (fs.existsSync(configPath)) {
    try {
        const configData = fs.readFileSync(configPath, 'utf8');
        config = {...config, ...JSON.parse(configData)};
        console.log('配置文件加载成功:', configPath);
    } catch (error) {
        console.error('读取配置文件失败:', error);
    }
} else {
    console.log('配置文件不存在，使用默认配置');
}

// ================= 数据库服务 =================
class DatabaseService {
    constructor() {
        this.connection = null;
        this.dbConfig = null;
        this.sqlQueries = null;
        this.isConnected = false;
    }

    // 加载数据库配置
    loadDbConfig() {
        try {
            const configPath = getConfigPath('config.json');
            if (fs.existsSync(configPath)) {
                const configData = fs.readFileSync(configPath, 'utf8');
                const dutyConfig = JSON.parse(configData);
                this.dbConfig = dutyConfig.database;
                this.sqlQueries = dutyConfig.sqlQueries;
                console.log('数据库配置加载成功:', configPath);
                return true;
            }
        } catch (error) {
            logger.error('加载数据库配置失败', {error: String(error)});
        }
        return false;
    }

    // 连接数据库
    async connect() {
        if (this.isConnected && this.connection) {
            return this.connection;
        }

        if (!this.loadDbConfig()) {
            throw new Error('数据库配置加载失败');
        }

        try {
            this.connection = await mysql.createConnection({
                host: this.dbConfig.host,
                port: this.dbConfig.port,
                user: this.dbConfig.user,
                password: this.dbConfig.password,
                database: this.dbConfig.database,
                charset: this.dbConfig.charset,
                acquireTimeout: 60000,
                timeout: 60000,
                reconnect: true
            });

            this.isConnected = true;
            logger.info('数据库连接成功');
            return this.connection;
        } catch (error) {
            this.isConnected = false;
            logger.error('数据库连接失败', {error: String(error)});
            throw error;
        }
    }

    // 断开连接
    async disconnect() {
        if (this.connection) {
            try {
                await this.connection.end();
                this.connection = null;
                this.isConnected = false;
                logger.info('数据库连接已断开');
            } catch (error) {
                logger.error('断开数据库连接失败', {error: String(error)});
            }
        }
    }

    // 查询值班数据
    async getDutyData(date = null) {
        if (!this.isConnected) {
            await this.connect();
        }

        try {
            const queryDate = date || new Date().toISOString().split('T')[0];

            // 从配置文件中读取SQL语句
            if (!this.sqlQueries || !this.sqlQueries.getDutyData) {
                throw new Error('查询语句配置缺失');
            }
            
            const sql = this.sqlQueries.getDutyData;

            const [rows] = await this.connection.execute(sql, [queryDate]);

            // 按岗位分类整理数据
            const result = {
                date: queryDate,
                leaders: [],    // 值班领导 (position = 1)
                officers: [],   // 值班民警 (position = 2)
                assistants: []  // 值班辅警 (position = 3)
            };

            rows.forEach(row => {
                const person = {
                    id: row.admin_id,
                    name: row.admin_name,
                    phone: row.duty_telephone || row.admin_telephone,
                    department: row.department_name,
                    remarks: row.remarks
                };

                // 根据岗位分类
                switch (row.position) {
                    case 1: // 值班领导
                        result.leaders.push(person);
                        break;
                    case 2: // 值班民警
                        result.officers.push(person);
                        break;
                    case 3: // 值班辅警
                        result.assistants.push(person);
                        break;
                    default:
                        // 如果没有明确岗位，根据排序判断
                        if (row.sort === 1) {
                            result.leaders.push(person);
                        } else if (row.sort <= 4) {
                            result.officers.push(person);
                        } else {
                            result.assistants.push(person);
                        }
                }
            });

            // 合并所有人员为统一的persons数组，供前端使用
            const allPersons = [...result.leaders, ...result.officers, ...result.assistants];

            logger.info('查询值班数据成功', {date: queryDate, leaders: result.leaders.length, officers: result.officers.length, assistants: result.assistants.length, total: allPersons.length});

            return {
                date: queryDate,
                persons: allPersons,
                // 保留分类数据供其他可能的用途
                leaders: result.leaders,
                officers: result.officers,
                assistants: result.assistants
            };
        } catch (error) {
            logger.error('查询值班数据失败', {error: String(error)});
            return {
                success: false,
                error: error.message
            };
        }
    }

    // 测试连接
    async testConnection() {
        try {
            await this.connect();
            const [rows] = await this.connection.execute('SELECT 1 as test');
            return {
                success: true,
                message: '数据库连接测试成功'
            };
        } catch (error) {
            return {
                success: false,
                error: error.message
            };
        }
    }
}

// 创建数据库服务实例
const dbService = new DatabaseService();

// 保持对窗口对象的全局引用，如果不这样做，当JavaScript对象被垃圾回收时，窗口会自动关闭
let mainWindow;
let tray = null;
let viteProcess = null;
// 退出标记：用于在拦截 close 时判断是否应真正退出
app.isQuiting = false;

// ================= 增强日志系统 =================
// 获取程序所在目录
const appPath = process.env.NODE_ENV === 'development'
    ? path.join(__dirname, '..')
    : process.resourcesPath || path.dirname(process.execPath);
const logDir = path.join(appPath, 'logs');
console.log('logDir', logDir)
try {
    mkdirSync(logDir, {recursive: true});
} catch {
}

// 日志配置
const LOG_CONFIG = {
    maxFileSize: 10 * 1024 * 1024, // 10MB
    maxFiles: 30, // 保留30天的日志
    flushInterval: 100, // 100ms防抖延迟
    consoleColors: {
        error: '\x1b[31m', // 红色
        warn: '\x1b[33m',  // 黄色
        info: '\x1b[36m',  // 青色
        debug: '\x1b[37m' // 白色
    },
    reset: '\x1b[0m'
};

let logQueue = [];
let isFlushingLogs = false;
let flushTimeout = null;
let currentDate = new Date().toISOString().slice(0, 10);
let currentLogFile = null;

// 获取当前日期的日志文件路径
function getCurrentLogFile() {
    const today = new Date().toISOString().slice(0, 10);
    if (today !== currentDate || !currentLogFile) {
        currentDate = today;
        currentLogFile = path.join(logDir, `app-${today}.log`);
    }
    return currentLogFile;
}

// 清理旧日志文件
function cleanupOldLogs() {
    try {
        const files = fs.readdirSync(logDir);
        const logFiles = files.filter(file => file.startsWith('app-') && file.endsWith('.log'));

        // 按日期排序，删除超过保留天数的文件
        logFiles.sort().forEach((file, index) => {
            if (index >= logFiles.length - LOG_CONFIG.maxFiles) {
                const filePath = path.join(logDir, file);
                try {
                    fs.unlinkSync(filePath);
                    console.log(`已删除旧日志文件: ${file}`);
                } catch (error) {
                    console.error(`删除日志文件失败: ${file}`, error);
                }
            }
        });
    } catch (error) {
        console.error('清理旧日志失败:', error);
    }
}

// 检查文件大小，必要时轮转
async function checkAndRotateLogFile() {
    try {
        const logFile = getCurrentLogFile();
        if (fs.existsSync(logFile)) {
            const stats = fs.statSync(logFile);
            if (stats.size > LOG_CONFIG.maxFileSize) {
                const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
                const rotatedFile = logFile.replace('.log', `-${timestamp}.log`);
                fs.renameSync(logFile, rotatedFile);
                console.log(`日志文件已轮转: ${rotatedFile}`);
            }
        }
    } catch (error) {
        console.error('日志文件轮转失败:', error);
    }
}

// 防抖机制：延迟批量写入日志
function scheduleFlush() {
    if (flushTimeout) {
        clearTimeout(flushTimeout);
    }
    flushTimeout = setTimeout(flushLogQueue, LOG_CONFIG.flushInterval);
}

// 异步写入日志队列
async function flushLogQueue() {
    if (isFlushingLogs || logQueue.length === 0) return;

    isFlushingLogs = true;
    flushTimeout = null;

    try {
        // 检查是否需要轮转文件
        await checkAndRotateLogFile();

        const batch = logQueue.splice(0); // 取出所有日志并清空队列
        const logFile = getCurrentLogFile();

        // 格式化日志条目
        const formattedLogs = batch.map(entry => {
            const timestamp = entry.timestamp;
            const level = entry.level.toUpperCase().padEnd(5);
            const pid = entry.pid || process.pid;
            const message = entry.message;
            const meta = entry.meta ? ` | ${JSON.stringify(entry.meta)}` : '';
            return `[${timestamp}] [${level}] [PID:${pid}] ${message}${meta}`;
        }).join('\n') + '\n';

        // 异步写入文件
        await appendFile(logFile, formattedLogs, {encoding: 'utf8'});

    } catch (error) {
        console.error('日志写入失败:', error);
    } finally {
        isFlushingLogs = false;

        // 如果在处理过程中又有新的日志，继续处理
        if (logQueue.length > 0) {
            scheduleFlush();
        }
    }
}

// 增强的日志写入函数
function writeLog(level, message, meta = null) {
    const validLevels = ['error', 'warn', 'info', 'debug'];
    if (!validLevels.includes(level)) {
        level = 'info';
    }

    const entry = {
        timestamp: new Date().toLocaleString('zh-CN', {
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit',
            hour12: false
        }).replace(/\//g, '-'),
        level,
        message,
        meta,
        pid: process.pid,
        memory: process.memoryUsage(),
        uptime: process.uptime()
    };

    // 添加到队列
    logQueue.push(entry);

    // 控制台输出（带颜色）
    const color = LOG_CONFIG.consoleColors[level] || LOG_CONFIG.consoleColors.info;
    const reset = LOG_CONFIG.reset;
    const metaStr = meta ? ` | ${JSON.stringify(meta)}` : '';
    console.log(`${color}[${level.toUpperCase()}]${reset} ${message}${metaStr}`);

    // 错误级别日志立即刷新
    if (level === 'error') {
        setImmediate(flushLogQueue);
    } else {
        scheduleFlush();
    }
}

// 便捷的日志方法
const logger = {
    error: (message, meta) => writeLog('error', message, meta),
    warn: (message, meta) => writeLog('warn', message, meta),
    info: (message, meta) => writeLog('info', message, meta),
    debug: (message, meta) => writeLog('debug', message, meta)
};

// 启动时清理旧日志
cleanupOldLogs();

// 定期清理（每天执行一次）
setInterval(cleanupOldLogs, 24 * 60 * 60 * 1000);

// ================= 数据拉取与缓存 =================
let latestWeathers = {items: [], updatedAt: 0};

// 批量获取天气预报信息
async function fetchWeatherForecast() {
    let weatherCity = config.weatherCity;
    logger.info('fetchWeatherForecast.start', {weatherCityNum: weatherCity.length});
    if (weatherCity.length === 0) {
        latestWeathers = {items: [], updatedAt: Date.now()};
        return latestWeathers;
    }
    let results = [];



    for (const s of weatherCity) {
        try {
            // 判定s.code是否获取过，如果已经获取直接提取缓存
            const cachedWeather = results.find(item => item.tqcode === s.code);
            if (cachedWeather) {
                results.push({
                    tqcode: s.code,
                    tqname: s.name,
                    weather: cachedWeather.weather
                });
                logger.info('fetchWeatherForecast.result', {tqcode: s.code, tqname: s.name, weather: cachedWeather.weather});
                continue;
            }

            const weather = await requestWeather(s.code);
            results.push({
                tqcode: s.code,
                tqname: s.name,
                weather
            });
            logger.info('fetchWeatherForecast.result', {tqcode: s.code, tqname: s.name, weather});
        } catch (error) {
            logger.error('fetchWeatherForecast.station_error', {tqcode: s.code, tqname: s.name, error: String(error)});
        }
    }

    latestWeathers = {items: results, updatedAt: Date.now()};
    logger.info('batch_fetch.done', {count: results.length});
    return latestWeathers;
}


// 根据区域tqcode代码获取天气预报信息，接口：http://www.nmc.cn/rest/weather?stationid=kUNHe&_=%E6%97%B6%E9%97%B4%E6%88%B3
async function requestWeather(tqcode) {
    const startTime = Date.now();
    try {
        logger.info('requestWeather.start', {tqcode, timestamp: new Date().toISOString()});

        // get 请求接口
        const options = {
            hostname: 'www.nmc.cn',
            path: `/rest/weather?stationid=${tqcode}&_=${new Date().getTime()}`,
            method: 'GET',
            timeout: 5000
        };

        const data = await new Promise((resolve, reject) => {
            const req = https.request(options, (res) => {
                let raw = '';
                res.setEncoding('utf8');
                res.on('data', (chunk) => (raw += chunk));
                res.on('end', () => {
                    logger.debug('requestWeather.response', {tqcode, statusCode: res.statusCode, headers: res.headers});
                    resolve(raw);
                });
            });
            req.on('error', reject);
            req.on('timeout', () => {
                const error = new Error('request timeout');
                logger.error('requestWeather.timeout', {tqcode, duration: Date.now() - startTime});
                req.destroy(error);
                reject(error);
            });
            req.end();
        });

        const weather = JSON.parse(data);
        const duration = Date.now() - startTime;
        logger.info('requestWeather.success', {
            tqcode,
            duration,
            dataLength: data.length,
            weatherKeys: Object.keys(weather || {})
        });
        return weather;
    } catch (e) {
        const duration = Date.now() - startTime;
        logger.error('requestWeather.error', {
            tqcode,
            error: String(e),
            duration,
            stack: e.stack
        });
        return null;
    }
}


// ================= 数据拉取与缓存 =================
let latestStations = {items: [], updatedAt: 0};

async function requestRiver(hlname, czname) {
    const startTime = Date.now();
    try {
        logger.info('requestRiver.start', {hlname, czname, timestamp: new Date().toISOString()});

        const postData = querystring.stringify({
            uid: '', qyid: '', hlname, czname, jjsw: '', OGRsw: '', num: 1, size: 20, v: 2
        });

        const options = {
            hostname: 'cqsw.slj.cq.gov.cn',
            path: '/hydrologyapi/stRiverR/getRiver',
            method: 'POST',
            headers: {
                'Accept': 'application/json, text/plain, */*',
                'Content-Type': 'application/x-www-form-urlencoded',
                'Content-Length': Buffer.byteLength(postData),
                'Origin': 'https://cqsw.slj.cq.gov.cn',
                'User-Agent': 'ElectronApp/1.0'
            },
            timeout: 5000
        };

        const data = await new Promise((resolve, reject) => {
            const req = https.request(options, (res) => {
                let raw = '';
                res.setEncoding('utf8');
                res.on('data', (chunk) => (raw += chunk));
                res.on('end', () => {
                    logger.debug('requestRiver.response', {
                        hlname,
                        czname,
                        statusCode: res.statusCode,
                        headers: res.headers,
                        dataLength: raw.length
                    });
                    resolve(raw);
                });
            });
            req.on('error', reject);
            req.on('timeout', () => {
                const error = new Error('request timeout');
                logger.error('requestRiver.timeout', {hlname, czname, duration: Date.now() - startTime});
                req.destroy(error);
                reject(error);
            });
            req.write(postData);
            req.end();
        });

        let list = [];
        try {
            logger.debug('requestRiver.raw_data', {hlname, czname, dataLength: data.length});
            const json = JSON.parse(data);
            list = json?.data?.pageinfo || [];

            // 清理数据：hnnm、rvnm移除空格，保留其他字段返回
            list = list.map((it) => ({
                ...it,
                hnnm: String(it.hnnm || '').trim(),
                rvnm: String(it.rvnm || '').trim(),
                addvcd: String(it.addvcd || '').trim(),
            }));

            logger.debug('requestRiver.parsed_data', {hlname, czname, count: list.length});
        } catch (e) {
            logger.error('requestRiver.parse_error', {
                hlname,
                czname,
                error: String(e),
                rawData: data.substring(0, 500), // 只记录前500字符
                stack: e.stack
            });
            list = [];
        }

        const duration = Date.now() - startTime;
        logger.info('requestRiver.success', {
            hlname,
            czname,
            count: Array.isArray(list) ? list.length : -1,
            duration,
            hasData: list.length > 0
        });
        return Array.isArray(list) ? list : [];
    } catch (e) {
        const duration = Date.now() - startTime;
        logger.error('requestRiver.error', {
            hlname,
            czname,
            error: String(e),
            duration,
            stack: e.stack
        });
        return [];
    }
}

// 批量拉取站点数据
async function fetchAllStationsNow() {
    const startTime = Date.now();
    const stations = Array.isArray(config.stations) ? config.stations : [];

    if (stations.length === 0) {
        logger.warn('batch_fetch.no_stations', {message: '配置中没有站点信息'});
        latestStations = {items: [], updatedAt: Date.now()};
        return latestStations;
    }

    logger.info('batch_fetch.start', {
        count: stations.length,
        stations: stations.map(s => ({hlname: s.hlname, czname: s.czname})),
        timestamp: new Date().toISOString()
    });

    const results = [];
    let successCount = 0;
    let errorCount = 0;

    for (const s of stations) {
        const hlname = String(s.hlname || '').trim();
        const czname = String(s.czname || '').trim();

        try {
            logger.debug('batch_fetch.processing_station', {czname, hlname});
            const list = await requestRiver(hlname, czname);

            // 精确匹配优先
            const exact = list.find((it) => String(it.rvnm || '').trim() === hlname && String(it.stnm || '').trim() === czname);
            const picked = exact || list[0];

            if (picked) {
                const stationData = {
                    name: String(picked.stnm || czname).trim(),
                    river: String(picked.rvnm || hlname).trim(),
                    addvcd: String(picked.addvcd || ''),
                    currentLevel: Number(picked.z ?? 0) || 0,
                    warningLevel: Number(picked.wrz ?? 0) || 0,
                    guaranteeLevel: Number(picked.grz ?? 0) || 0,
                    tm: String(picked.tm || ''),
                    height: Number(s.height) || 700,
                    hasData: true,

                    // 接口返回的完整字段
                    frgrd: String(picked.frgrd || ''),
                    hnnm: String(picked.hnnm || ''),
                    ogrsw: Number(picked.ogrsw ?? 0) || 0,
                    q: picked.q,
                    stcd: String(picked.stcd || ''),
                    sttp: String(picked.sttp || ''),
                    sw: Number(picked.sw ?? 0) || 0,
                    usfl: String(picked.usfl || ''),
                    wptn: String(picked.wptn || '')
                };

                results.push(stationData);
                successCount++;

                logger.debug('batch_fetch.station_success', {
                    czname,
                    hlname,
                    currentLevel: stationData.currentLevel,
                    hasWarning: stationData.currentLevel > stationData.warningLevel,
                    hasGuarantee: stationData.currentLevel > stationData.guaranteeLevel
                });
            } else {
                logger.warn('batch_fetch.no_data_found', {czname, hlname, listLength: list.length});

                results.push({
                    name: czname,
                    river: hlname,
                    addvcd: '',
                    currentLevel: 0,
                    warningLevel: 0,
                    guaranteeLevel: 0,
                    tm: '',
                    height: Number(s.height) || 700,
                    hasData: false,

                    // 无数据时的默认字段
                    frgrd: '',
                    hnnm: '',
                    ogrsw: 0,
                    q: null,
                    stcd: '',
                    sttp: '',
                    sw: 0,
                    usfl: '',
                    wptn: ''
                });
                errorCount++;
            }
        } catch (error) {
            logger.error('batch_fetch.station_error', {
                czname,
                hlname,
                error: String(error),
                stack: error.stack
            });

            results.push({
                name: czname,
                river: hlname,
                addvcd: '',
                currentLevel: 0,
                warningLevel: 0,
                guaranteeLevel: 0,
                tm: '',
                height: Number(s.height) || 700,
                hasData: false,

                // 无数据时的默认字段
                frgrd: '',
                hnnm: '',
                ogrsw: 0,
                q: null,
                stcd: '',
                sttp: '',
                sw: 0,
                usfl: '',
                wptn: ''
            });
            errorCount++;
        }
    }

    latestStations = {items: results, updatedAt: Date.now()};
    const duration = Date.now() - startTime;

    logger.info('batch_fetch.completed', {
        totalCount: results.length,
        successCount,
        errorCount,
        duration,
        updateTime: new Date().toISOString(),
        hasWarnings: results.some(r => r.hasData && r.currentLevel > r.warningLevel),
        hasGuarantees: results.some(r => r.hasData && r.currentLevel > r.guaranteeLevel)
    });

    return latestStations;
}

// 获取可用端口
function getAvailablePort() {
    // 使用配置文件中的端口
    return config.port || 5172;
}

// 启动Vite开发服务器（仅在开发模式下）
function startViteServer() {
    const port = getAvailablePort();

    // 仅在开发模式下启动Vite开发服务器
    if (!app.isPackaged) {
        try {
            const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
            // 启动Vite开发服务器，使用配置文件中的设置
            viteProcess = spawn(npmCmd, ['run', 'dev'], {
                cwd: path.join(__dirname, '..'),
                stdio: ['pipe', 'pipe', 'pipe'],
                shell: true
            });
            logger.info('vite.start', {url: `http://127.0.0.1:${port}`, pid: viteProcess.pid});

            // 给Vite服务器一些启动时间
            setTimeout(() => {
                logger.info('vite.startup_delay_complete', {port});
            }, 2000);

            // 监听Vite进程输出
            if (viteProcess.stdout) {
                viteProcess.stdout.on('data', (data) => {
                    const output = data.toString().trim();
                    logger.debug('vite.stdout', {output});
                    if (output.includes('Local:') || output.includes('ready') || output.includes('5172') || output.includes('http://')) {
                        logger.info('vite.ready_detected', {output});
                    }
                });
            }

            if (viteProcess.stderr) {
                viteProcess.stderr.on('data', (data) => {
                    const output = data.toString().trim();
                    logger.error('vite.stderr', {output});
                });
            }

            // 添加进程启动检测
            viteProcess.on('spawn', () => {
                logger.info('vite.process_spawned', {pid: viteProcess.pid});
            });

            try {
                viteProcess.on('exit', (code, signal) => {
                    logger.error('vite.process_exit', {code, signal});
                });
                viteProcess.on('error', (err) => {
                    logger.error('vite.process_error', {error: String(err), stack: err.stack});
                });
            } catch {
            }
        } catch (error) {
            logger.error('vite.start_failed', {error: String(error), stack: error.stack});
        }
    }

    return port;
}

// 创建浏览器窗口
function waitForViteReady(port, timeoutMs = 10000, intervalMs = 1000) {
    const start = Date.now();
    let attemptCount = 0;
    return new Promise((resolve, reject) => {
        const check = () => {
            attemptCount++;
            logger.debug('vite.check_attempt', {port, attempt: attemptCount, elapsed: Date.now() - start});

            const req = http.get({hostname: '127.0.0.1', port, path: '/', timeout: 2000}, (res) => {
                // 任何响应都代表已就绪
                res.resume();
                logger.info('vite.wait_ok', {port, elapsed: Date.now() - start, statusCode: res.statusCode});
                resolve();
            });
            req.on('error', (err) => {
                const elapsed = Date.now() - start;
                logger.debug('vite.check_error', {port, attempt: attemptCount, elapsed, error: String(err)});

                if (elapsed > timeoutMs) {
                    logger.error('vite.wait_timeout', {port, elapsed, timeoutMs, attempts: attemptCount});
                    reject(new Error(`Vite server not ready on port ${port} after ${timeoutMs}ms (${attemptCount} attempts)`));
                } else {
                    logger.debug('vite.wait_retry', {port, elapsed, nextCheck: intervalMs, attempt: attemptCount});
                    setTimeout(check, intervalMs);
                }
            });
        };
        check();
    });
}

function createWindow() {
    let port;
    // 仅在开发环境启动Vite服务器
    if (!app.isPackaged) {
        port = startViteServer();
    } else {
        port = getAvailablePort();
    }

    // 获取当前屏幕类型对应的页面路径
    const screenType = config.screenType || 'main';
    const targetPage = config.screenPages && config.screenPages[screenType]
        ? config.screenPages[screenType]
        : '/';

    logger.info('screen.config', {screenType, targetPage});
    let windowIconPath;
    // 尝试多个可能的图标路径
    const possibleIconPaths = [
        path.join(path.dirname(process.execPath), 'resources', 'dist', 'logo.png'),
        path.join(process.resourcesPath, 'public', 'logo.png'),
        path.join(__dirname, '..', 'app.asar.unpacked', 'public', 'logo.png'),
        path.join(__dirname, '..', 'public', 'logo.png'),
        path.join(path.dirname(process.execPath), 'resources', 'public', 'logo.png'),
        path.join(path.dirname(process.execPath), 'public', 'logo.png')
    ];

    // 找到第一个存在的图标文件
    for (const testPath of possibleIconPaths) {
        if (fs.existsSync(testPath)) {
            windowIconPath = testPath;
            break;
        }
    }


    // 创建浏览器窗口
    mainWindow = new BrowserWindow({
        icon: windowIconPath,
        width: 800,
        height: 600,
        fullscreen: true, // 全屏显示
        alwaysOnTop: true, // 置顶显示
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
            nodeIntegration: false,
            contextIsolation: true,
            webSecurity: false, // 允许加载本地文件
            allowRunningInsecureContent: true,
            devTools: true // 确保开发者工具在生产环境中可用
        }
    });


    // 取消默认菜单栏
    Menu.setApplicationMenu(null);

    // 根据环境加载不同的页面
    if (app.isPackaged) {
        // 生产环境：加载本地文件
        let indexPath;

        // 尝试多个可能的路径
        const possiblePaths = [
            // 1. resources 目录下的 dist
            path.join(process.resourcesPath, 'dist', 'index.html'),
            // 2. app.asar.unpacked 目录下的 dist
            path.join(__dirname, '..', 'app.asar.unpacked', 'dist', 'index.html'),
            // 3. 相对路径的 dist
            path.join(__dirname, '..', 'dist', 'index.html'),
            // 4. 执行目录下的 dist
            path.join(path.dirname(process.execPath), 'resources', 'dist', 'index.html'),
            // 5. 直接在应用目录下的 dist
            path.join(path.dirname(process.execPath), 'dist', 'index.html')
        ];

        // 找到第一个存在的文件
        for (const testPath of possiblePaths) {
            if (fs.existsSync(testPath)) {
                indexPath = testPath;
                break;
            }
        }

        if (!indexPath) {
            // 如果都没找到，使用第一个路径作为默认值，并记录错误
            indexPath = possiblePaths[0];
            logger.error('load.production.index_not_found', {
                attemptedPaths: possiblePaths,
                selectedPath: indexPath,
                resourcesPath: process.resourcesPath,
                execPath: process.execPath,
                dirname: __dirname
            });
        }

        logger.info('load.production', {indexPath, targetPage, appPath: process.resourcesPath || path.dirname(process.execPath)});

        // 检查文件是否存在，如果不存在则记录详细错误信息
        if (!fs.existsSync(indexPath)) {
            const possiblePaths = [
                path.join(__dirname, '..', 'dist', 'index.html'),
                path.join(process.resourcesPath || path.dirname(process.execPath), 'dist', 'index.html'),
                path.join(app.getAppPath(), 'dist', 'index.html')
            ];

            logger.error('load.production.index_not_found', {
                attemptedPaths: possiblePaths,
                selectedPath: indexPath,
                resourcesPath: process.resourcesPath,
                execPath: process.execPath,
                dirname: __dirname,
                cwd: process.cwd(),
                appPath: app.getAppPath()
            });
        }

        // 使用 file:// 协议加载，确保相对路径正确解析
        // 移除开头的斜杠，生成正确的 hash 路由
        const hashPath = targetPage.startsWith('/') ? targetPage.slice(1) : targetPage;
        const fileUrl = 'file:///' + path.resolve(indexPath).replace(/\\/g, '/') + '#' + hashPath;

        logger.info('load.production.file_url', {fileUrl, indexPath, hashPath});

        // 设置额外的安全策略，允许加载本地资源
        mainWindow.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => {
            // 确保本地文件可以正确加载
            if (details.url.startsWith('file://')) {
                details.requestHeaders['User-Agent'] = 'Electron/' + process.versions.electron;
            }
            callback({ cancel: false, requestHeaders: details.requestHeaders });
        });

        /*// 改进的样式加载机制
        const loadStyles = () => {
            // 首先尝试找到并读取CSS文件
            const assetsDir = path.join(path.dirname(indexPath), 'assets');

            if (fs.existsSync(assetsDir)) {
                try {
                    const files = fs.readdirSync(assetsDir);
                    const cssFiles = files.filter(f => f.endsWith('.css'));

                    cssFiles.forEach(cssFile => {
                        try {
                            const cssPath = path.join(assetsDir, cssFile);
                            const cssContent = fs.readFileSync(cssPath, 'utf8');
                            mainWindow.webContents.insertCSS(cssContent);
                            logger.info('load.production.css_injected', {cssFile});
                        } catch (error) {
                            logger.error('load.production.css_inject_failed', {error: String(error)});
                        }
                    });
                } catch (error) {
                    logger.error('load.production.css_read_failed', {error: String(error)});
                }
            }

            // 强制注入基础样式，确保关键样式不丢失
            mainWindow.webContents.insertCSS(`
                /!* 基础样式保障 *!/
                body {
                    margin: 0 !important;
                    padding: 0 !important;
                    width: 1080px !important;
                    height: 3848px !important;
                    background: #0a0e1a !important;
                    color: white !important;
                    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif !important;
                    overflow-x: hidden !important;
                }

                #root {
                    width: 100% !important;
                    height: 100% !important;
                }

                /!* 确保所有Tailwind样式都能正确应用 *!/
                * {
                    box-sizing: border-box !important;
                }

                /!* 强制重置关键样式 *!/
                .container, .flex, .grid, .block, .inline-block, .inline, .hidden {
                    display: block !important;
                }

                /!* 确保颜色样式正确应用 *!/
                .text-white {
                    color: white !important;
                }

                .bg-blue-500 {
                    background-color: #3b82f6 !important;
                }

                .bg-red-500 {
                    background-color: #ef4444 !important;
                }

                .bg-green-500 {
                    background-color: #10b981 !important;
                }
            `);
        };

        // 页面加载完成后立即注入样式
        mainWindow.webContents.once('did-finish-load', () => {
            loadStyles();

            // 2秒后再次检查并修复样式
            setTimeout(() => {
                mainWindow.webContents.executeJavaScript(`
                    // 检查TailwindCSS是否生效
                    const testElement = document.createElement('div');
                    testElement.className = 'bg-blue-500 text-white p-4';
                    testElement.textContent = 'TailwindCSS测试';
                    document.body.appendChild(testElement);

                    // 如果3秒后测试元素仍然没有样式，重新加载CSS
                    setTimeout(() => {
                        const computedStyle = window.getComputedStyle(testElement);
                        if (computedStyle.backgroundColor === 'rgba(0, 0, 0, 0)' ||
                            computedStyle.backgroundColor === 'transparent') {
                            console.log('TailwindCSS样式加载失败，重新加载页面');
                            window.location.reload();
                        } else {
                            testElement.remove();
                        }
                    }, 3000);
                `);
            }, 2000);

            logger.info('load.production.css_injected');
        });*/

        mainWindow.loadURL(fileUrl);
    } else {
        // 开发环境：等待Vite开发服务器就绪后再加载
        logger.info('vite.wait_start', {port, targetPage});

        // 先等待5秒让Vite服务器有时间启动
        setTimeout(() => {
            logger.info('vite.wait_attempt', {port, targetPage});

            const fullUrl = `http://127.0.0.1:${port}${targetPage}`;

            // 先简单测试一下端口是否可访问
            const testReq = http.get({hostname: '127.0.0.1', port, path: '/', timeout: 2000}, (res) => {
                logger.info('vite.quick_test_ok', {port, statusCode: res.statusCode, targetPage});
                mainWindow.loadURL(fullUrl);
            });
            testReq.on('error', (err) => {
                logger.debug('vite.quick_test_failed', {port, error: String(err), targetPage});
                // 如果快速测试失败，使用完整的等待机制
                waitForViteReady(port)
                    .then(() => {
                        logger.info('vite.wait_ok', {port, targetPage});
                        mainWindow.loadURL(fullUrl);
                    })
                    .catch((err) => {
                        logger.error('vite.wait_failed', {port, error: String(err), stack: err.stack, targetPage});
                        // 兜底：直接尝试加载，不等待检测
                        logger.info('vite.fallback_load', {port, targetPage});
                        mainWindow.loadURL(fullUrl);
                    });
            });
        }, 5000);

        // 添加额外的超时保护
        setTimeout(() => {
            logger.info('vite.timeout_fallback', {port, targetPage});
            const fullUrl = `http://127.0.0.1:${port}${targetPage}`;
            mainWindow.loadURL(fullUrl);
        }, 15000);
    }

    // 打开开发者工具（临时定位空白与卡死）- 改为通过F12快捷键控制
    // try {
    //     mainWindow.webContents.openDevTools({mode: 'detach'});
    // } catch {
    // }

    // 观察窗口加载与无响应
    try {
        mainWindow.webContents.on('did-finish-load', () => {
            logger.info('window.did_finish_load');
        });
        mainWindow.webContents.on('did-fail-load', (_e, errorCode, errorDescription, validatedURL) => {
            logger.error('window.did_fail_load', {errorCode, errorDescription, validatedURL});
        });
        mainWindow.on('unresponsive', () => {
            logger.error('window.unresponsive');
        });
    } catch {
    }

    // 当窗口关闭时触发
    mainWindow.on('closed', function () {
        // 取消对窗口对象的引用，通常会存储窗口在数组中，这是删除相应元素的时候
        mainWindow = null;
    });

    // 注册快捷键退出全屏
    globalShortcut.register('Escape', () => {
        if (mainWindow && mainWindow.isFullScreen()) {
            mainWindow.setFullScreen(false);
            mainWindow.setAlwaysOnTop(false);
        }
    });

    // 注册Ctrl+Q退出程序
    globalShortcut.register('CommandOrControl+Q', () => {
        app.isQuiting = true;
        try {
            globalShortcut.unregisterAll();
        } catch {
        }
        if (viteProcess) {
            try {
                viteProcess.kill();
            } catch {
            }
        }
        if (tray) {
            try {
                tray.destroy();
            } catch {
            }
        }
        app.quit();
    });

    // 注册F12快捷键切换开发者工具
    const f12Registered = globalShortcut.register('F12', () => {
        if (mainWindow && !mainWindow.isDestroyed()) {
            try {
                if (mainWindow.webContents.isDevToolsOpened()) {
                    mainWindow.webContents.closeDevTools();
                    logger.info('devtools.closed');
                } else {
                    mainWindow.webContents.openDevTools({mode: 'detach'});
                    logger.info('devtools.opened');
                }
            } catch (error) {
                logger.error('devtools.toggle_failed', {error: String(error)});
            }
        }
    });

    // 注册F11快捷键切换全屏
    const f11Registered = globalShortcut.register('F11', () => {
        if (mainWindow && !mainWindow.isDestroyed()) {
            try {
                const isFullScreen = mainWindow.isFullScreen();
                mainWindow.setFullScreen(!isFullScreen);
                // 切换全屏时同步设置alwaysOnTop状态
                if (!isFullScreen) {
                    // 进入全屏时设置置顶
                    mainWindow.setAlwaysOnTop(true);
                } else {
                    // 退出全屏时取消置顶
                    mainWindow.setAlwaysOnTop(false);
                }
                logger.info('fullscreen.toggled', {isFullScreen: !isFullScreen});
            } catch (error) {
                logger.error('fullscreen.toggle_failed', {error: String(error)});
            }
        }
    });

    if (f12Registered) {
        logger.info('f12_shortcut.registered');
    } else {
        logger.error('f12_shortcut.registration_failed');
    }

    if (f11Registered) {
        logger.info('f11_shortcut.registered');
    } else {
        logger.error('f11_shortcut.registration_failed');
    }

    // 如果配置为最小化到托盘，则隐藏主窗口
    if (config.minimizeToTray) {
        mainWindow.on('close', (event) => {
            if (!app.isQuiting) {
                event.preventDefault();
                mainWindow.hide();
                return false;
            }
        });
    }
}

// 创建系统托盘
function createTray(port) {
    // 创建系统托盘图标
    try {
        const {nativeImage} = require('electron');
        let iconPath;

        if (app.isPackaged) {
            // 尝试多个可能的图标路径
            const possibleIconPaths = [
                path.join(process.resourcesPath, 'public', 'logo.png'),
                path.join(path.dirname(process.execPath), 'resources', 'dist', 'logo.png'),
                path.join(__dirname, '..', 'app.asar.unpacked', 'public', 'logo.png'),
                path.join(__dirname, '..', 'public', 'logo.png'),
                path.join(path.dirname(process.execPath), 'resources', 'public', 'logo.png'),
                path.join(path.dirname(process.execPath), 'public', 'logo.png')
            ];

            // 找到第一个存在的图标文件
            for (const testPath of possibleIconPaths) {
                if (fs.existsSync(testPath)) {
                    iconPath = testPath;
                    break;
                }
            }

            if (!iconPath) {
                iconPath = possibleIconPaths[0]; // 默认路径
                logger.error('tray.icon_not_found', {
                    attemptedPaths: possibleIconPaths,
                    selectedPath: iconPath
                });
            }
        } else {
            // 开发环境路径
            iconPath = path.join(__dirname, '..', 'public', 'logo.png');
        }
        
        logger.info('tray.icon_path', {iconPath, exists: fs.existsSync(iconPath)});
        let image = nativeImage.createFromPath(iconPath);
        if (image.isEmpty && image.isEmpty()) {
            logger.error('tray.icon_invalid', {iconPath});
        }
        tray = new Tray(image);
    } catch (e) {
        logger.error('tray.create_failed', {error: String(e), stack: e.stack});
        return;
    }
    try {
        tray.setToolTip('Project Bolt');
    } catch {
    }

    // 创建上下文菜单
    const contextMenu = Menu.buildFromTemplate([
        {
            label: '打开主界面',
            click: () => {
                if (mainWindow) {
                    mainWindow.show();
                    mainWindow.focus();
                } else {
                    createWindow();
                }
            }
        },
        {
            label: '打开 Web 调试页面',
            click: () => {
                const {shell} = require('electron');
                shell.openExternal(`http://localhost:${port}`);
            }
        },
        {
            label: '切换开发者工具 (F12)',
            click: () => {
                if (mainWindow && !mainWindow.isDestroyed()) {
                    try {
                        if (mainWindow.webContents && !mainWindow.webContents.isDestroyed()) {
                            if (mainWindow.webContents.isDevToolsOpened()) {
                                mainWindow.webContents.closeDevTools();
                                logger.info('devtools.closed');
                            } else {
                                mainWindow.webContents.openDevTools({mode: 'detach'});
                                logger.info('devtools.opened');
                            }
                        } else {
                            logger.error('devtools.toggle_failed', {reason: 'webContents destroyed'});
                        }
                    } catch (e) {
                        logger.error('devtools.toggle_exception', {error: String(e), stack: e.stack});
                    }
                } else {
                    logger.error('devtools.toggle_failed', {reason: 'mainWindow missing or destroyed'});
                }
            }
        },
        {
            label: '切换全屏 (F11)',
            click: () => {
                if (mainWindow && !mainWindow.isDestroyed()) {
                    try {
                        const isFullScreen = mainWindow.isFullScreen();
                        mainWindow.setFullScreen(!isFullScreen);
                        // 切换全屏时同步设置alwaysOnTop状态
                        if (!isFullScreen) {
                            // 进入全屏时设置置顶
                            mainWindow.setAlwaysOnTop(true);
                        } else {
                            // 退出全屏时取消置顶
                            mainWindow.setAlwaysOnTop(false);
                        }
                        logger.info('tray.fullscreen.toggled', {isFullScreen: !isFullScreen});
                    } catch (error) {
                        logger.error('tray.fullscreen.toggle_failed', {error: String(error)});
                    }
                } else {
                    logger.error('tray.fullscreen.toggle_failed', {reason: 'mainWindow missing or destroyed'});
                }
            }
        },
        {
            label: '重启服务',
            click: () => {
                if (viteProcess) {
                    try {
                        viteProcess.kill();
                    } catch {
                    }
                }
                const newPort = startViteServer();
                if (mainWindow && !app.isPackaged) {
                    waitForViteReady(newPort)
                        .then(() => {
                            mainWindow.loadURL(`http://localhost:${newPort}`);
                        })
                        .catch(() => {
                            mainWindow.loadURL(`http://localhost:${newPort}`);
                        });
                }
            }
        },
        {
            label: '更新数据',
            click: () => {
                // 记录点击日志并确保窗口与 webContents 可用
                try {
                    logger.info('tray.refresh_click');
                } catch {
                }
                if (mainWindow && !mainWindow.isDestroyed()) {
                    try {
                        if (mainWindow.webContents && !mainWindow.webContents.isDestroyed()) {
                            logger.info('tray.refresh_send');
                            mainWindow.webContents.send('refresh-now');
                        } else {
                            logger.error('tray.refresh_send_failed', {reason: 'webContents destroyed'});
                        }
                    } catch (e) {
                        logger.error('tray.refresh_send_exception', {error: String(e), stack: e.stack});
                    }
                } else {
                    logger.error('tray.refresh_send_failed', {reason: 'mainWindow missing or destroyed'});
                }
            }
        },
        {
            label: '强制清理进程',
            click: () => {
                logger.info('tray.force_cleanup_clicked');
                forceCleanupAllProcesses();
            }
        },
        {
            label: '退出程序',
            click: () => {
                logger.info('tray.quit_clicked');
                app.isQuiting = true;

                // 清理定时器
                if (fetchInterval) {
                    clearInterval(fetchInterval);
                    fetchInterval = null;
                    logger.info('tray.quit.interval_cleared');
                }

                // 清理快捷键
                try {
                    globalShortcut.unregisterAll();
                    logger.info('tray.quit.shortcuts_cleared');
                } catch (err) {
                    logger.error('tray.quit.shortcuts_error', {error: String(err), stack: err.stack});
                }

                // 结束Vite进程
                if (viteProcess) {
                    try {
                        viteProcess.kill('SIGTERM');
                        logger.info('tray.quit.vite_killed');
                        // 如果进程没有在2秒内退出，强制杀死
                        setTimeout(() => {
                            if (viteProcess && !viteProcess.killed) {
                                try {
                                    viteProcess.kill('SIGKILL');
                                    logger.info('tray.quit.vite_force_killed');
                                } catch (err) {
                                    logger.error('tray.quit.vite_force_kill_error', {
                                        error: String(err),
                                        stack: err.stack
                                    });
                                }
                            }
                        }, 2000);
                    } catch (err) {
                        logger.error('tray.quit.vite_kill_error', {error: String(err), stack: err.stack});
                    }
                }

                // 销毁托盘
                if (tray) {
                    try {
                        tray.destroy();
                        logger.info('tray.quit.tray_destroyed');
                    } catch (err) {
                        logger.error('tray.quit.tray_destroy_error', {error: String(err), stack: err.stack});
                    }
                }

                // 关闭所有窗口
                try {
                    const windows = BrowserWindow.getAllWindows();
                    windows.forEach(window => {
                        if (!window.isDestroyed()) {
                            window.destroy();
                        }
                    });
                    logger.info('tray.quit.windows_destroyed');
                } catch (err) {
                    logger.error('tray.quit.windows_destroy_error', {error: String(err), stack: err.stack});
                }

                logger.info('tray.quit.completed');

                // 延迟执行强制清理，确保正常退出流程先完成
                setTimeout(() => {
                    forceCleanupAllProcesses();
                }, 1000);

                app.quit();
            }
        }
    ]);

    tray.setContextMenu(contextMenu);

    // 点击托盘图标显示/隐藏主窗口
    tray.on('click', () => {
        if (mainWindow) {
            if (mainWindow.isVisible()) {
                mainWindow.hide();
            } else {
                mainWindow.show();
            }
        }
    });

    // 强制右键弹出菜单（兼容某些环境右键不弹的问题）
    try {
        tray.on('right-click', () => {
            try {
                tray.popUpContextMenu();
            } catch (e) {
                logger.error('tray.popup_failed', {error: String(e), stack: e.stack});
            }
        });
    } catch {
    }

    logger.info('tray.ready');
}

// 设置开机自启动
function setAutoStart() {
    // 根据配置文件设置开机自启动
    app.setLoginItemSettings({
        openAtLogin: config.autoStart,
        path: process.execPath
    });
}

// 当Electron完成初始化并准备创建浏览器窗口时调用此方法
app.whenReady().then(() => {
    // 测试日志系统
    logger.info('app.startup', {version: app.getVersion(), platform: process.platform});

    createWindow();

    // 创建系统托盘
    const port = getAvailablePort();
    createTray(port);

    // 设置开机自启动
    setAutoStart();

    // 启动定时器：按配置周期批量拉取
    const intervalMinutes = Number(config.fetchIntervalMinutes || 10);
    const ms = Math.max(1, intervalMinutes) * 60 * 1000;

    logger.info('scheduler.setup', {intervalMinutes, intervalMs: ms});


    const screenType = config.screenType || 'main';
    logger.info('app.whenReady ', {screenType});
    switch (screenType) {
        case 'main':
            // 先立即拉一次
            fetchAllStationsNow().catch(() => {
            });
            // 定时拉取
            fetchInterval = setInterval(() => {
                fetchAllStationsNow().catch(() => {
                });
            }, ms);
            break
        case 'duty':
            break
        case 'dispatch':
            break
        case 'weather':
            // 天气预报
            logger.info('update config.weatherCity', config.weatherCity)
            fetchWeatherForecast().catch(() => {
            });
            // 定时拉取天气
            const weatherInterval = setInterval(() => {
                fetchWeatherForecast().catch(() => {
                });
            }, ms);
            break
    }
    app.on('activate', function () {
        // 通常在macOS上，当点击dock图标且没有其他窗口打开时，会重新创建一个窗口
        if (BrowserWindow.getAllWindows().length === 0) createWindow();
    });
});

// 当所有窗口都关闭时退出
app.on('window-all-closed', function () {
    // 在macOS上，除非用户用Cmd + Q确定退出，否则应用程序和菜单栏通常会保持活动状态
    if (process.platform !== 'darwin') app.quit();
});

// 全局变量存储定时器引用
let fetchInterval = null;

// 强制清理所有相关进程
function forceCleanupAllProcesses() {
    logger.info('force_cleanup.start');

    try {
        // 清理所有node进程（除了当前进程）
        const {exec} = require('child_process');
        const platform = process.platform;

        if (platform === 'win32') {
            // Windows: 清理所有node.exe进程（除了当前进程）
            exec('tasklist /FI "IMAGENAME eq node.exe" /FO CSV', (error, stdout) => {
                if (!error && stdout) {
                    const lines = stdout.split('\n');
                    lines.forEach(line => {
                        if (line.includes('node.exe')) {
                            const parts = line.split(',');
                            if (parts.length > 1) {
                                const pid = parts[1].replace(/"/g, '').trim();
                                if (pid && pid !== process.pid.toString()) {
                                    try {
                                        exec(`taskkill /F /PID ${pid}`, (killError) => {
                                            if (!killError) {
                                                logger.info('force_cleanup.node_killed', {pid});
                                            }
                                        });
                                    } catch (err) {
                                        logger.error('force_cleanup.node_kill_error', {
                                            pid,
                                            error: String(err),
                                            stack: err.stack
                                        });
                                    }
                                }
                            }
                        }
                    });
                }
            });
        } else {
            // Unix-like systems: 清理所有node进程（除了当前进程）
            exec('ps aux | grep node | grep -v grep', (error, stdout) => {
                if (!error && stdout) {
                    const lines = stdout.split('\n');
                    lines.forEach(line => {
                        const parts = line.trim().split(/\s+/);
                        if (parts.length > 1) {
                            const pid = parts[1];
                            if (pid && pid !== process.pid.toString()) {
                                try {
                                    exec(`kill -9 ${pid}`, (killError) => {
                                        if (!killError) {
                                            logger.info('force_cleanup.node_killed', {pid});
                                        }
                                    });
                                } catch (err) {
                                    logger.error('force_cleanup.node_kill_error', {
                                        pid,
                                        error: String(err),
                                        stack: err.stack
                                    });
                                }
                            }
                        }
                    });
                }
            });
        }
    } catch (err) {
        logger.error('force_cleanup.error', {error: String(err), stack: err.stack});
    }

    logger.info('force_cleanup.completed');
}

// 在应用程序退出之前清理资源
app.on('before-quit', () => {
    app.isQuiting = true;
    logger.info('app.before_quit.start');

    // 清理定时器
    if (fetchInterval) {
        clearInterval(fetchInterval);
        fetchInterval = null;
        logger.info('app.before_quit.interval_cleared');
    }

    // 清理快捷键
    try {
        globalShortcut.unregisterAll();
        logger.info('app.before_quit.shortcuts_cleared');
    } catch (err) {
        logger.error('app.before_quit.shortcuts_error', {error: String(err), stack: err.stack});
    }

    // 结束Vite进程
    if (viteProcess) {
        try {
            viteProcess.kill('SIGTERM');
            logger.info('app.before_quit.vite_killed');
            // 如果进程没有在3秒内退出，强制杀死
            setTimeout(() => {
                if (viteProcess && !viteProcess.killed) {
                    try {
                        viteProcess.kill('SIGKILL');
                        logger.info('app.before_quit.vite_force_killed');
                    } catch (err) {
                        logger.error('app.before_quit.vite_force_kill_error', {error: String(err), stack: err.stack});
                    }
                }
            }, 3000);
        } catch (err) {
            logger.error('app.before_quit.vite_kill_error', {error: String(err), stack: err.stack});
        }
    }

    // 销毁托盘
    if (tray) {
        try {
            tray.destroy();
            logger.info('app.before_quit.tray_destroyed');
        } catch (err) {
            logger.error('app.before_quit.tray_destroy_error', {error: String(err), stack: err.stack});
        }
    }

    // 关闭所有窗口
    try {
        const windows = BrowserWindow.getAllWindows();
        windows.forEach(window => {
            if (!window.isDestroyed()) {
                window.destroy();
            }
        });
        logger.info('app.before_quit.windows_destroyed');
    } catch (err) {
        logger.error('app.before_quit.windows_destroy_error', {error: String(err), stack: err.stack});
    }

    logger.info('app.before_quit.completed');
});

// IPC通信示例
ipcMain.handle('get-app-info', async () => {
    return {
        version: app.getVersion(),
        name: app.getName()
    };
});

// 暴露配置给渲染进程
ipcMain.handle('get-config', async () => {
    return {
        fetchIntervalMinutes: config.fetchIntervalMinutes || 10,
        stations: Array.isArray(config.stations) ? config.stations : []
    };
});

// 供渲染进程写日志
ipcMain.handle('renderer-write-log', async (_event, payload) => {
    // 立即返回，避免渲染端等待文件 IO
    try {
        const {level = 'info', message = 'renderer', meta} = payload || {};
        logger[level] ? logger[level](message, meta) : logger.log(level, message, meta);
        return {ok: true};
    } catch (e) {
        try {
            logger.error('renderer-write-log.failed', {error: String(e), stack: e.stack});
        } catch {
        }
        return {ok: false, error: String(e)};
    }
});

// 批量拉取与读取最新数据 IPC
ipcMain.handle('fetch-all-stations-now', async () => {
    try {
        const res = await fetchAllStationsNow();
        return {ok: true, ...res};
    } catch (e) {
        logger.error('batch_fetch.error', {error: String(e), stack: e.stack});
        return {ok: false, error: String(e)};
    }
});
// 批量拉取与读取最新数据 天气
ipcMain.handle('fetch-weather', async () => {
    try {
        const res = await fetchWeatherForecast();
        return {ok: true, ...res};
    } catch (e) {
        logger.error('fetch-weather.error', {error: String(e), stack: e.stack});
        return {ok: false, error: String(e)};
    }
});

ipcMain.handle('get-latest-stations', async () => {
    try {
        return {ok: true, ...latestStations};
    } catch (e) {
        return {ok: false, error: String(e)};
    }
});

// 数据库相关IPC处理程序
// 获取值班配置
ipcMain.handle('get-duty-config', async () => {
    try {
        const configPath = getConfigPath('config.json');
        if (fs.existsSync(configPath)) {
            const configData = fs.readFileSync(configPath, 'utf8');
            const fullConfig = JSON.parse(configData);
            console.log('fullConfig====>',fullConfig)
            // 只返回 dutySettings 部分，符合前端期望的结构
            const dutyConfig = fullConfig.dutySettings;
            dutyConfig.mockData = fullConfig.mockData
            return {
                success: true,
                data: dutyConfig
            };
        }
    } catch (error) {
        logger.error('get-duty-config.error', {error: String(error), stack: error.stack});
        return {
            success: false,
            error: error.message
        };
    }
});

// 获取值班数据
ipcMain.handle('get-duty-data', async (_event, date, useMockData = false) => {
    try {
        const result = await dbService.getDutyData(date, useMockData);
        return {
            success: true,
            data: result
        };
    } catch (error) {
        logger.error('get-duty-data.error', {error: String(error), stack: error.stack});
        return {
            success: false,
            error: error.message
        };
    }
});

// 测试数据库连接
ipcMain.handle('test-db-connection', async () => {
    try {
        const result = await dbService.testConnection();
        return {
            success: result.success,
            data: result,
            error: result.success ? undefined : result.message
        };
    } catch (error) {
        logger.error('test-db-connection.error', {error: String(error), stack: error.stack});
        return {
            success: false,
            error: error.message
        };
    }
});

// 请求水位接口并按精确匹配过滤结果
ipcMain.handle('fetch-river', async (_event, {hlname, czname}) => {
    // 添加重试机制
    const maxRetries = 3;
    const retryDelay = 2000; // 2秒重试延迟

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            logger.info('fetch_river.start', {hlname, czname, attempt});
            const postData = querystring.stringify({
                uid: '',
                qyid: '',
                hlname,
                czname,
                jjsw: '',
                OGRsw: '',
                num: 1,
                size: 20,
                v: 2
            });

            const options = {
                hostname: 'cqsw.slj.cq.gov.cn',
                path: '/hydrologyapi/stRiverR/getRiver',
                method: 'POST',
                headers: {
                    'Accept': 'application/json, text/plain, */*',
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'Content-Length': Buffer.byteLength(postData),
                    'Origin': 'https://cqsw.slj.cq.gov.cn',
                    'User-Agent': 'ElectronApp/1.0'
                },
                timeout: 10000
            };

            const data = await new Promise((resolve, reject) => {
                const req = https.request(options, (res) => {
                    let raw = '';
                    res.setEncoding('utf8');
                    res.on('data', (chunk) => (raw += chunk));
                    res.on('end', () => resolve(raw));
                });
                req.on('error', reject);
                req.on('timeout', () => {
                    req.destroy(new Error('request timeout'));
                });
                req.write(postData);
                req.end();
            });

            const json = JSON.parse(data);
            const list = json?.data?.pageinfo || [];
            // 过滤：河流与测站名称精确匹配（去除两侧空白）
            const normalized = list.filter((item) => {
                const rv = String(item.rvnm || '').trim();
                const st = String(item.stnm || '').trim();
                return rv.includes(hlname) && st.includes(czname);
            });

            const result = {
                ok: true,
                items: normalized,
                rawCount: Array.isArray(list) ? list.length : 0
            };
            logger.info('fetch_river.ok', {
                hlname,
                czname,
                rawCount: result.rawCount,
                matched: result.items.length,
                attempt
            });
            return result;
        } catch (err) {
            logger.error('fetch_river.error', {hlname, czname, error: String(err), stack: err.stack, attempt});

            // 如果是最后一次尝试，返回错误
            if (attempt === maxRetries) {
                return {ok: false, error: String(err)};
            }

            // 等待后重试
            await new Promise(resolve => setTimeout(resolve, retryDelay));
        }
    }
});